#include <algorithm>
#include <cstdio>

#define ll long long
#define lson (root << 1)
#define rson (root << 1 | 1)
const int maxn = 1000005;
ll sum[maxn << 2];
ll a[maxn], dep[maxn];
ll s[maxn];
ll n, m, qwq;
ll maxd;

void build(ll root, ll l, ll r,
           ll d) //相比一般的线段树多统计了深度，并维护最大深度
{
  if (l == r) {
    sum[root] = a[l];
    dep[l] = d;
    maxd = std::max(maxd, d);
    return;
  }
  ll mid = (l + r) >> 1;
  build(lson, l, mid, d + 1);
  build(rson, mid + 1, r, d + 1);
  sum[root] = sum[lson] + sum[rson];
}

ll query(ll root, ll l, ll r, ll t,
         ll tt) // tt表示当前结点以上的那些结点权值和，t的意义看下面
{
  if (l == r)
    return (1 << t) * (tt + sum[root]); //返回的值是所有的叶子节点，返回值是路径权值和
                                        //乘以 2^(maxd - dep[i])
  ll mid = (l + r) >> 1;
  return query(lson, l, mid, t - 1, tt + sum[root]) +
         query(rson, mid + 1, r, t - 1, tt + sum[root]);
}

ll gcd(ll x, ll y) {
  if (y == 0)
    return x;
  return gcd(y, x % y);
}

int main() {
  scanf("%lld%lld%lld", &n, &m, &qwq);
  for (int i = 1; i <= n; i++)
    scanf("%lld", a + i);
  build(1, 1, n, 1);
  ll ans = query(1, 1, n, maxd - 1, 0), y = 1 << (maxd - 1);
  ll yue = gcd(y, qwq); //约分，别中途超出范围了
  y /= yue;
  qwq /= yue;
  for (ll i = 1; i <= n; i++)
    s[i] = s[i - 1] + (((1 << dep[i]) - 1) << (maxd - dep[i]));
  //后面加的式子其实是(2^(dep[i]) - 1) * 2^(maxd - dep[i])
  while (m--) {
    ll l, r, w;
    scanf("%lld%lld%lld", &l, &r, &w);
    ans += (s[r] - s[l - 1]) * w;
    printf("%lld\n", ans / y * qwq); // ans / y是真正的期望，y取2^(maxd - 1)
  }
  return 0;
}